<template>
  <GroupPage title="角色权限" group-title="用户角色" sub-title="定义角色的功能权限，设置页面权限和操作权限">
    <template #groupPrefix>
      <div class="mx-7 mt-7">
        <a-input v-model:value="roleNameKeyword" placeholder="搜索角色">
          <template #prefix>
            <Icon type="icon-sousuo" class="text-color-secondary" />
          </template>
        </a-input>
      </div>
    </template>
    <template #group>
      <SpinSkeleton :loading="tableLoading" :show-empty="true" :empty-text="emptyText" :data="tableData">
        <GroupList
          :data="tableData"
          id-key="roleId"
          title-key="roleName"
          des-key="roleDescription"
          :selected-id="curRoleId"
          :item-opacity="loadingRoleUsers"
          :has-oper="true"
          @select="handleCheckModal"
          @edit="showUpdateRole"
          @del="showDelRole"
        >
          <template #titleSuffix="{ data }: { data: RoleItem }">
            <span
              class="inline-block ml-3.5 rounded-xl px-2 bg-opacity-10 text-xs"
              :class="[isAdminRole(data) ? 'bg-color-active text-color-active' : 'bg-color-success text-color-success']"
            >
              {{ isAdminRole(data) ? "系统默认" : "自定义" }}
            </span>
          </template>
        </GroupList>
      </SpinSkeleton>
    </template>
    <template #groupSuffix>
      <div class="mb-4.5 mx-7">
        <PermissionBtn :btn-props="{ block: true }" :oper-type="OperPermissionType.MANAGE" @click="openCreateRole">
          新增用户角色
        </PermissionBtn>
      </div>
    </template>
    <template #contentTitle>
      {{ curRoleItem ? curRoleItem.roleName : "--" }}
      <span :class="{ 'text-gray-300': loadingRoleUsers }">
        {{ loadingRoleUsers ? t("common.loading") : `(${userData.length})` }}
      </span>
    </template>
    <template #contentTitleOper>
      <a-button type="link" class="icon-text-middle !pr-0" @click="viewPermission">
        <Icon type="icon-permission-active" class="text-color-active text-2xl" />
        查看权限
      </a-button>
    </template>
    <template #content>
      <SearchForm
        v-model:keyword="userNameKeyword"
        :part-search-model="partSearchModel"
        class="mt-7 mx-7"
        :select-data="selectData"
        :keyword-search-data="keywordSearchData"
        add-btn-text="添加成员"
        :add-btn-oper-type="OperPermissionType.MANAGE"
        del-btn-text="移除成员"
        :del-btn-props="{ onClick: delUsers, disabled: selectedRowKeys.length === 0 }"
        :del-btn-oper-type="OperPermissionType.MANAGE"
        @add="showAddUser"
        @search="onSearch"
      />
      <div class="flex-1 overflow-hidden mx-7 mb-4.5">
        <SlTable
          row-key="userId"
          top-border
          :columns="columns"
          :data-source="userData"
          :loading="loadingRoleUsers"
          :pagination="undefined"
          :row-selection="{
            type: 'checkbox',
            selectedRowKeys,
            onChange,
            getCheckboxProps,
          }"
        >
          <template #bodyCell="{ record, column }">
            <div v-if="column.dataIndex === 'oper'">
              <PermissionBtn
                :oper-type="OperPermissionType.MANAGE"
                :btn-props="{ type: 'link', danger: true, disabled: record.isSystem }"
                @click="delUser(record)"
              >
                移除
              </PermissionBtn>
            </div>
            <div v-else-if="column.dataIndex === 'userName'">
              <span class="align-middle">{{ record.userName }}</span>
              <span
                v-if="record.isSystem"
                class="inline-block ml-3.5 rounded-xl px-2 bg-opacity-10 text-xs bg-color-warn text-color-warn"
              >
                创建者
              </span>
            </div>
          </template>
        </SlTable>
      </div>
    </template>
    <CreateRoleModal
      v-model:visible="createVisible"
      :model="roleModel"
      :model-form-setting="roleModelFormSetting"
      :is-enterprise="isEnterprise"
      :exclude-role-ids="''"
      :handle-user="handleUser"
      @create="onCreateRole"
    />
    <!-- 新增授权用户 -->
    <a-modal v-model:visible="addAuthUserVisible" :width="872" :title="t('aiot.role.addAuthUser')" @ok="addUser">
      <UserSelect
        ref="addAuthUserSelectIns"
        v-model:value="authUserIds"
        :disabled-value="selectedUserIds"
        :has-org="isEnterprise"
        :exclude-role-ids="excludeRoleIds"
        :handle-user="handleUser"
        :is-user-disable="(item) => !!item.isSystem"
      />
    </a-modal>
    <!-- 查看或编辑功能权限 -->
    <InsideDrawer v-model:visible="funcAuthDrawerVisible" w-class="lg:!w-252" :title="authTitle">
      <SelectApps
        v-if="isEnterprise"
        ref="selectAppsRef"
        v-model:value="selectedApps"
        class="mb-4.5"
        :disabled="!editingAuth"
        :required="editingAuth"
        :except-apps="exceptApps"
      ></SelectApps>
      <AuthList
        v-model:value="authValueToUpdate"
        :is-update="editingAuth && isUpdateAuthList"
        :server-value="curRolePermissions"
        :is-admin="isAdmin"
      />
      <div v-show="authErrMes" ref="authErrMesDiv" class="text-color-danger mt-2"> {{ authErrMes }} </div>
      <template #footer>
        <a-space v-if="editingAuth" :size="16" class="float-right">
          <a-button class="!text-xs sm:!text-base" @click="toggleEditingAuth(false)">
            {{ t("common.cancel") }}
          </a-button>
          <a-button type="primary" class="!text-xs sm:!text-base" @click="updateFuncAuth">
            {{ t("common.ok") }}
          </a-button>
        </a-space>
        <div v-else class="float-right">
          <a-tooltip v-if="isAdmin" title="无法修改管理员权限" placement="left">
            <a-button :disabled="isAdmin" @click="toggleEditingAuth(true)">编辑</a-button>
          </a-tooltip>
          <PermissionBtn v-else :oper-type="OperPermissionType.MANAGE" @click="toggleEditingAuth(true)">
            编辑
          </PermissionBtn>
        </div>
      </template>
    </InsideDrawer>
    <!-- 编辑角色基本信息 -->
    <CURDDialog
      ref="roleIns"
      :update-title="t('aiot.role.editRole')"
      :show-options="showOptions"
      :model="roleModel"
      :model-form-setting="roleModelFormSetting"
      :table-data="tableData"
      :curd="curd"
      id-key="roleId"
      :reload-table="reloadRoleList"
      :cannot-edit-ids="cannotEditIds"
    />
  </GroupPage>
</template>
<script lang="ts" setup>
import { message } from "ant-design-vue";
import { computed, nextTick, onMounted, ref, shallowRef, watch } from "vue";
import { useI18n } from "/@/locales/useI18n";
import Icon from "/@/components/Icon.vue";

import type {
  AuthorizedRoleFunctionsParams,
  OrgUserTreeItem,
  RoleFunctionMenuItem,
  RoleItem,
  RoleSearchModel,
  RoleUserItem,
} from "/@/api/aiot/role/models";

import { AdminRoleType, RoleType } from "/@/api/aiot/role/models";

import CreateRoleModal from "./CreateRoleModal.vue";
import UserSelect from "/@/components/UserSelect.vue";
import InsideDrawer from "/@/components/InsideDrawer.vue";
import { Api, authorizedRoleFunctions, authorizedRoleUsers, removeAuthorizedRoleUsers } from "/@/api/aiot/role";
import { Api as orgApi } from "/@/api/aiot/organization";
import { useCURD } from "/@/hooks/useCURD";
import { RequestMethodEnum } from "/@/api/req/httpEnum";
import SpinSkeleton from "/@/components/common/SpinSkeleton.vue";
import { CURDAction } from "/@/components/CURDDialog/models";
import type { ShowCURDModalOptions } from "/@/components/CURDDialog/models";
import TreeTransfer from "/@/components/TreeTransfer.vue";
import { loopItem } from "/@/utils/treeData";
import GroupPage from "/@/components/GroupPage.vue";
import SlEmpty from "/@/components/SlEmpty.vue";
import { useEmptyText } from "/@/hooks/useEmptyText";
import { useRoleModel } from "./useRoleModel";
import { OperPermissionType } from "/@/api/aiot/role/models";
import { KeywordSearchItem, SelectItem, UserSelectExpose } from "/@/types/components";
import InfoModal from "/@/components/InfoModal";
import { AiotSubApp, getAiotSubAppData } from "/@/base/data";
import { cloneDeep } from "lodash-es";
import { UserItem } from "/@/api/aiot/organization/models";
import { usePermission } from "/@/hooks/usePermission";

const props = defineProps<{
  isEnterprise?: boolean;
}>();

const { t } = useI18n();
/**
 * common
 */
const {
  tableData: orgData,
  tableLoading: orgLoading,
  reloadTable: reloadOrgData,
} = useCURD<OrgUserTreeItem>({
  getDataUrl: orgApi.getOrgTreeVoByName,
  getDataMethod: RequestMethodEnum.POST,
  loadOnMounted: false,
  onLoadSuccess(data) {
    loopItem(data, (item) => {
      item.id = item.companyId as string;
      item.name = item.companyShortName as string;
      item.type = "ORG";
      item.transfterable = false;
    });
  },
});
async function getOrgData() {
  if (orgData.value.length === 0) {
    await reloadOrgData();
  }
  return orgData.value;
}
onMounted(async () => {
  //加载角色列表
  await reloadTable({ roleName: "" });
  //加载角色用户列表
  if (tableData.value.length > 0) {
    curRoleId.value = tableData.value[0].roleId as string;
  } else {
    curRoleId.value = "";
  }
});
const { roleModel, roleModelFormSetting } = useRoleModel();
/**
 * 角色列表
 */
const { judgePermissionByOperType } = usePermission();
const managePermission = judgePermissionByOperType(OperPermissionType.MANAGE);
const curRoleId = ref("");
const curRoleItem = computed(() => {
  return tableData.value.find((item) => item.roleId === curRoleId.value);
});
const showOptions = ref<ShowCURDModalOptions>();
function showUpdateRole(record) {
  showOptions.value = {
    action: CURDAction.UPDATE,
    record,
  };
}
function showDelRole(record) {
  showOptions.value = {
    action: CURDAction.DELETE,
    record,
    message: t("aiot.role.delMes", { name: record.roleName }),
  };
}
function isAdminRole(roleItem: RoleItem) {
  return roleItem.roleType === AdminRoleType.system || roleItem.roleType === AdminRoleType.tenant;
}
const { emptyText, modelForEmptyText } = useEmptyText();
const cannotEditIds = ref<string[]>([]);
let allRoleData: RoleItem[] = [];
const { tableData, tableLoading, reloadTable, curd, searchModel } = useCURD<RoleItem, RoleSearchModel>({
  getDataUrl: Api.getRolesByName,
  getDataMethod: RequestMethodEnum.POST,
  updateUrl: Api.updateRole,
  deleteUrl: Api.deleteRoleByIds,
  loadOnMounted: false,
  onLoadSuccess(data) {
    allRoleData = data;
    const ids: string[] = [];
    data.forEach((record) => {
      if (!managePermission || isAdminRole(record)) {
        ids.push(record.roleId as string);
      }
      record.disableOper = !managePermission || isAdminRole(record);
    });
    cannotEditIds.value = ids;
  },
});
const isAdmin = computed(() => {
  if (curRoleItem.value) {
    return isAdminRole(curRoleItem.value);
  }
  return false;
});
const roleNameKeyword = ref("");
watch(roleNameKeyword, (v) => {
  const newData: RoleItem[] = [];
  allRoleData.forEach((el) => {
    if (el.roleName?.includes(v)) {
      newData.push(el);
    }
  });
  tableData.value = newData;
});
// const btnDisabledMes = computed(() => {
//   if (tableData.value.length === 0) {
//     return t("aiot.role.plzChooseRole");
//   }
//   if (isAdmin.value) {
//     return t("aiot.role.admin");
//   }
//   return "";
// });
watch(
  searchModel,
  (v) => {
    modelForEmptyText.value = v;
  },
  { deep: true }
);
//同时刷新当前行数据
async function reloadRoleList(model?) {
  await reloadTable(model);
  if (!curRoleItem.value) {
    if (tableData.value.length > 0) {
      curRoleId.value = tableData.value[0].roleId as string;
    } else {
      curRoleId.value = "";
    }
  }
}
const roleIns = ref();
//当打开了角色编辑窗口 切换角色同步更新里面内容
function handleCheckModal({ el }) {
  if (loadingRoleUsers.value) return;
  curRoleId.value = el.roleId;
  if (roleIns.value?.isOpen()) {
    showOptions.value = { action: CURDAction.UPDATE, record: el };
  }
}
watch(curRoleId, async (v) => {
  if (v === "") return;
  const item = curRoleItem.value;
  if (item) {
    //加载角色用户列表
    await reloadRoleUser({ model: { roleId: item.roleId as string } });
    roleUserInited.value = true;
  }
  refreshRolePermissions();
});
const createVisible = ref(false);
function openCreateRole() {
  excludeRoleIds.value = curRoleId.value;
  createVisible.value = true;
}
function onCreateRole() {
  reloadRoleList();
  reloadRoleUser({ model: { roleId: curRoleId.value } });
}
/**
 * 授权用户
 */
const roleUserInited = ref(false);
const allData = ref<RoleUserItem[]>();
const {
  tableData: userData,
  tableLoading: loadingRoleUsers,
  reloadTable: reloadRoleUser,
} = useCURD<RoleUserItem, { roleId: string }>({
  getPageUrl: Api.getUsersByRoleId,
  loadOnMounted: false,
  //加载全部授权用户
  pageSize: 1000,
  loadFilter(data) {
    data.sort((a, b) => {
      return a.isSystem ? -1 : 1;
    });
    return data;
  },
  onLoadSuccess(data) {
    allData.value = data;
    curCompanyId.value = "";
    userNameKeyword.value = "";
    partSearchModel.value = {
      companyId: "",
    };
  },
});
function getCheckboxProps(record: RoleUserItem) {
  if (record.isSystem) {
    return { disabled: true };
  }
}
const addAuthUserVisible = ref(false);
const addAuthUserSelectIns = ref<UserSelectExpose>();
const authUserIds = ref<string[]>([]);
const selectedUserIds = ref<string[]>([]);
function handleUser(user: UserItem) {
  const roleId = user.roleId;
  if (roleId) {
    const item = tableData.value.find((el) => el.roleId === roleId);
    if (item) {
      user.roleName = item.roleName;
    }
  }
}
//打开选择授权用户窗口
const excludeRoleIds = ref<string>("");
let firstOpenAddAuthUser = true;
function showAddUser() {
  if (!allData.value) return;
  selectedUserIds.value = allData.value.map((el) => el.userId as string);
  excludeRoleIds.value = curRoleId.value;
  addAuthUserVisible.value = true;
  if (firstOpenAddAuthUser) {
    firstOpenAddAuthUser = false;
  } else if (addAuthUserSelectIns.value) {
    addAuthUserSelectIns.value.reset();
  }
  //清空
  authUserIds.value = [];
  getOrgData();
}
//授权
function addUser() {
  if (authUserIds.value.length === 0) {
    return message.warning(t("aiot.role.plzSelUser"));
  }
  handleAddUser();
}

async function handleAddUser() {
  const re = await authorizedRoleUsers({
    roleId: curRoleItem.value?.roleId,
    usersList: authUserIds.value,
  });
  if (re) {
    addAuthUserVisible.value = false;
    message.success(t("common.operSuccess"));
    reloadRoleUser({ model: { roleId: curRoleItem.value?.roleId as string } });
  }
}
//搜索
const partSearchModel = ref<Record<string, any>>();
const selectData = ref<SelectItem[]>(
  props.isEnterprise
    ? [
        {
          label: t("common.department"),
          value: "",
          key: "companyId",
          isTreeSelect: true,
          containerWidth: 260,
          props: {
            treeData: [],
            loading: true,
            fieldNames: { label: "companyShortName", value: "companyId" },
            treeNodeFilterProp: "companyShortName",
            treeNodeLabelProp: "companyShortName",
            virtual: false,
          },
        },
      ]
    : []
);
onMounted(async () => {
  if (props.isEnterprise) {
    const data = await getOrgData();
    const selectProps = selectData.value[0].props;
    if (selectProps) {
      let compData: OrgUserTreeItem[] = [
        { companyId: "", companyShortName: "全部", id: "", name: "全部", type: "ORG", key: "" },
      ];
      selectProps.loading = false;
      selectProps.treeData = compData.concat(data) as any;
    }
  }
});
const columns = ref([
  { dataIndex: "userName", title: "姓名" },
  { dataIndex: "companyShortName", title: "部门" },
  { dataIndex: "oper", title: "操作" },
]);
if (!props.isEnterprise) {
  columns.value.splice(1, 1);
}
const keywordSearchData: KeywordSearchItem[] = [
  {
    key: "searchText",
    label: "姓名",
  },
];
const curCompanyId = ref("");
const userNameKeyword = ref("");
function delUsers() {
  if (selectedRowKeys.value.length === 0) {
    return message.warning(t("aiot.role.plzSelUser"));
  }
  handleDel(selectedRowKeys.value, "您确定移除所选用户吗？");
}
function delUser(record: RoleUserItem) {
  handleDel([record.userId], "您确定移除该用户吗？");
}
function handleDel(userIds: string[], content: string) {
  InfoModal.confirm({
    content,
    async onOk() {
      const re = await removeAuthorizedRoleUsers({
        roleId: curRoleItem.value?.roleId,
        usersList: userIds,
      });
      if (re) {
        message.success(t("common.operSuccess"));
        reloadRoleUser({ model: { roleId: curRoleItem.value?.roleId as string } });
      }
    },
  });
}
const selectedRowKeys = ref<string[]>([]);
function onChange(keys) {
  selectedRowKeys.value = keys;
}
function onSearch(model) {
  curCompanyId.value = model.companyId;
}
watch([curCompanyId, userNameKeyword], ([id, val]) => {
  if (!allData.value) return;
  const searchData: RoleUserItem[] = [];
  const filterIds: string[] = [];
  if (id) {
    filterIds.push(id);
    const orgData = selectData.value[0].props?.treeData as OrgUserTreeItem[];
    loopItem<OrgUserTreeItem>(orgData, (item) => {
      if (item.companyId === id) {
        if (item.children) {
          loopItem<OrgUserTreeItem>(item.children, (item) => {
            filterIds.push(item.companyId as string);
          });
        }
        return false;
      }
    });
  }
  allData.value.forEach((item) => {
    if (
      ((filterIds.length > 0 && filterIds.includes(item.companyId)) || filterIds.length === 0) &&
      (!val || item.userName.indexOf(val) !== -1)
    ) {
      searchData.push(item);
    }
  });
  userData.value = searchData;
});
/**
 * 功能权限
 */
const editingAuth = ref(false);
const authErrMes = ref("");
const authErrMesDiv = shallowRef<HTMLDivElement>();
const authTitle = computed(() => {
  const item = curRoleItem.value;
  if (!item) return "";
  return `${editingAuth.value ? "编辑权限" : "查看权限"}(${item.roleName})`;
});
const curRolePermissions = ref<RoleFunctionMenuItem[]>([]);
const funcAuthDrawerVisible = ref(false);
const selectedApps = ref<AiotSubApp[]>([]);
const isUpdateAuthList = ref(true);
const exceptApps = ref<AiotSubApp[]>([]);
watch(
  selectedApps,
  (apps) => {
    const hasAiot = apps.includes(AiotSubApp.AIOT);
    if (hasAiot || !props.isEnterprise) {
      isUpdateAuthList.value = true;
      refreshRolePermissions(false);
    } else {
      isUpdateAuthList.value = false;
      curRolePermissions.value = [];
    }
    authErrMes.value = "";
  },
  { deep: true }
);
const selectAppsRef = ref();
//刷新功能权限
function refreshRolePermissions(refreshApp = true) {
  const item = curRoleItem.value;
  if (item) {
    if (item.rolePermissions) {
      const value = JSON.parse(item.rolePermissions) as RoleFunctionMenuItem[];
      curRolePermissions.value = value;
    } else {
      curRolePermissions.value = [];
    }
    if (refreshApp) {
      if (isAdmin.value) {
        const apps = getAiotSubAppData().map((el) => el.value);
        selectedApps.value = apps;
        //企业管理员角色，因数据源问题，应去掉小程序的授权
        exceptApps.value = [AiotSubApp.IOPM_MINIPROGRAM];
      } else {
        selectedApps.value = item.applicationPermissions as AiotSubApp[];
        exceptApps.value = [];
      }
    }
  }
}
function viewPermission() {
  //每次打开都刷新一次 当前角色的权限值
  refreshRolePermissions();
  funcAuthDrawerVisible.value = true;
}
const authValueToUpdate = ref<AuthorizedRoleFunctionsParams>({
  roleFolderPermissions: [],
  roleMenuPermissions: [],
  applicationPermissions: [],
});
async function updateFuncAuth() {
  const item = curRoleItem.value;
  if (!item) return;
  try {
    await selectAppsRef.value.validate();
    if (isUpdateAuthList.value) {
      if (authValueToUpdate.value.roleMenuPermissions?.length === 0) {
        authErrMes.value = "请设置权限";
        nextTick(() => {
          (authErrMesDiv.value?.parentNode as HTMLDivElement).scrollTop = 9999;
        });
        return;
      }
    }
    authValueToUpdate.value.applicationPermissions = selectedApps.value;
    const re = await authorizedRoleFunctions({
      roleId: item.roleId,
      ...authValueToUpdate.value,
    });
    if (re) {
      funcAuthDrawerVisible.value = false;
      message.success(t("common.operSuccess"));
      //刷新角色列表数据
      await reloadTable();
    }
  } catch (err) {
    (authErrMesDiv.value?.parentNode as HTMLDivElement).scrollTop = 0;
  }
}
let preSelectedApps: AiotSubApp[] = [];
let prePermissions: RoleFunctionMenuItem[] = [];
function toggleEditingAuth(isEdit) {
  if (isEdit) {
    preSelectedApps = [...selectedApps.value];
    prePermissions = cloneDeep(curRolePermissions.value);
    editingAuth.value = true;
  } else {
    selectedApps.value = preSelectedApps;
    curRolePermissions.value = prePermissions;
    editingAuth.value = false;
  }
}
watch(funcAuthDrawerVisible, (v) => {
  if (!v) {
    editingAuth.value = false;
  }
});
//
</script>
